home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / rdist-6.1 / rdist-6 / rdist-6.1.0-linuxpl2 / src / common.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-16  |  19.5 KB  |  973 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char RCSid[] = 
  36. "$Id: common.c,v 6.71 1994/04/20 18:11:03 mcooper Exp $";
  37.  
  38. static char sccsid[] = "@(#)common.c";
  39.  
  40. static char copyright[] =
  41. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  42.  All rights reserved.\n";
  43. #endif /* !lint */
  44.  
  45. /*
  46.  * Things common to both the client and server.
  47.  */
  48.  
  49. #include "defs.h"
  50. #if    defined(NEED_UTIME_H)
  51. #include <utime.h>
  52. #endif    /* defined(NEED_UTIME_H) */
  53.  
  54. /*
  55.  * Variables common to both client and server
  56.  */
  57. char            host[MAXHOSTNAMELEN];    /* Name of this host */
  58. UID_T            userid = (UID_T)-1;    /* User's UID */
  59. GID_T            groupid = (GID_T)-1;    /* User's GID */
  60. char               *homedir = NULL;        /* User's $HOME */
  61. char               *locuser = NULL;        /* Local User's name */
  62. int            isserver = FALSE;    /* We're the server */
  63. int             amchild = 0;        /* This PID is a child */
  64. int            do_fork = 1;        /* Fork child process */
  65. char               *currenthost = NULL;    /* Current client hostname */
  66. char               *progname = NULL;    /* Name of this program */
  67. int            rem_r = -1;        /* Client file descriptor */
  68. int            rem_w = -1;        /* Client file descriptor */
  69. struct passwd           *pw = NULL;        /* Local user's pwd entry */
  70. int             contimedout = FALSE;    /* Connection timed out */
  71. int            proto_version = -1;    /* Protocol version */
  72. int            rtimeout = RTIMEOUT;    /* Response time out */
  73. jmp_buf            finish_jmpbuf;        /* Finish() jmp buffer */
  74. char              **realargv;        /* Real main() argv */
  75. int            realargc;        /* Real main() argc */
  76. opt_t            options = 0;        /* Global install options */
  77.  
  78.  
  79. /*
  80.  * Set program name
  81.  */
  82. extern void setprogname(argv)
  83.     char **argv;
  84. {
  85.     register char *cp;
  86.  
  87.     if (!progname) {
  88.         progname = strdup(argv[0]);
  89.         if (cp = strrchr(progname, '/'))
  90.             progname = cp + 1;
  91.     }
  92. }
  93.  
  94. /*
  95.  * Do run-time initialization
  96.  */
  97. extern int init(argc, argv, envp)
  98.     /*ARGSUSED*/
  99.     int argc;
  100.     char **argv;
  101.     char **envp;
  102. {
  103.     register int i;
  104.  
  105.     if (!isserver)
  106.         (void) signal(SIGSEGV, sighandler);
  107.  
  108.     setprogname(argv);
  109.  
  110.     /*
  111.      * Save a copy of our argc and argv before setargs() overwrites them
  112.      */
  113.     realargc = argc;
  114.     realargv = (char **) xmalloc(sizeof(char *) * (argc+1));
  115.     for (i = 0; i < argc; i++)
  116.         realargv[i] = strdup(argv[i]);
  117.  
  118. #if    defined(SETARGS)
  119.     setargs_settup(argc, argv, envp);
  120. #endif    /* SETARGS */
  121.  
  122.     pw = getpwuid(userid = getuid());
  123.     if (pw == NULL) {
  124.         error("Your user id (%d) is not known to this system.",
  125.               getuid());
  126.         return(-1);
  127.     }
  128.  
  129.     debugmsg(DM_MISC, "UserID = %d pwname = '%s' home = '%s'\n",
  130.          userid, pw->pw_name, pw->pw_dir);
  131.     homedir = strdup(pw->pw_dir);
  132.     locuser = strdup(pw->pw_name);
  133.     groupid = pw->pw_gid;
  134.     gethostname(host, sizeof(host));
  135.  
  136.     /*
  137.      * If we're not root, disable paranoid ownership checks
  138.      * since normal users cannot chown() files.
  139.      */
  140.     if (!isserver && userid != 0) {
  141.         FLAG_ON(options, DO_NOCHKOWNER);
  142.         FLAG_ON(options, DO_NOCHKGROUP);
  143.     }
  144.  
  145.     return(0);
  146. }
  147.  
  148. /*
  149.  * Finish things up before ending.
  150.  */
  151. extern void finish()
  152. {
  153.     extern jmp_buf finish_jmpbuf;
  154.  
  155.     debugmsg(DM_CALL, 
  156.          "finish() called: do_fork = %d amchild = %d isserver = %d",
  157.          do_fork, amchild, isserver);
  158.     cleanup();
  159.  
  160.     /*
  161.      * There's no valid finish_jmpbuf for the rdist master parent.
  162.      */
  163.     if (!do_fork || amchild || isserver) {
  164.         longjmp(finish_jmpbuf, 1);
  165.         /*NOTREACHED*/
  166.         error("Unexpected failure of longjmp() in finish()");
  167.         exit(2);
  168.     } else
  169.         exit(1);
  170. }
  171.  
  172. /*
  173.  * Handle lost connections
  174.  */
  175. extern void lostconn()
  176. {
  177.     /* Prevent looping */
  178.     (void) signal(SIGPIPE, SIG_IGN);
  179.  
  180.     rem_r = rem_w = -1;    /* Ensure we don't try to send to server */
  181.     checkhostname();
  182.     error("Lost connection to %s", 
  183.           (currenthost) ? currenthost : "(unknown)");
  184.  
  185.     finish();
  186. }
  187.  
  188. /*
  189.  * Do a core dump
  190.  */
  191. extern void coredump()
  192. {
  193.     error("Segmentation violation - dumping core [PID = %d, %s]",
  194.           getpid(), 
  195.           (isserver) ? "isserver" : ((amchild) ? "amchild" : "parent"));
  196.     abort();
  197.     /*NOTREACHED*/
  198.     fatalerr("Abort failed - no core dump.  Exiting...");
  199. }
  200.  
  201. /*
  202.  * General signal handler
  203.  */
  204. extern void sighandler(sig)
  205.     int sig;
  206. {
  207.     debugmsg(DM_CALL, "sighandler() received signal %d\n", sig);
  208.  
  209.     switch (sig) {
  210.     case SIGALRM:
  211.         contimedout = TRUE;
  212.         checkhostname();
  213.         error("Response time out");
  214.         finish();
  215.         break;
  216.  
  217.     case SIGPIPE:
  218.         lostconn();
  219.         break;
  220.  
  221.     case SIGFPE:
  222.         debug = !debug;
  223.         break;
  224.  
  225.     case SIGSEGV:
  226.         coredump();
  227.         break;
  228.  
  229.     case SIGHUP:
  230.     case SIGINT:
  231.     case SIGQUIT:
  232.     case SIGTERM:
  233.         finish();
  234.         break;
  235.  
  236.     default:
  237.         fatalerr("No signal handler defined for signal %d.", sig);
  238.     }
  239. }
  240.  
  241. /*
  242.  * Function to actually send the command char and message to the
  243.  * remote host.
  244.  */
  245. static int sendcmdmsg(cmd, msg)
  246.     char cmd;
  247.     char *msg;
  248. {
  249.     int len;
  250.  
  251.     if (rem_w < 0)
  252.         return(-1);
  253.  
  254.     /*
  255.      * All commands except C_NONE should have a newline
  256.      */
  257.     if (cmd != C_NONE && !strchr(msg + 1, '\n'))
  258.         (void) strcat(msg + 1, "\n");
  259.  
  260.     if (cmd == C_NONE)
  261.         len = strlen(msg);
  262.     else {
  263.         len = strlen(msg + 1) + 1;
  264.         msg[0] = cmd;
  265.     }
  266.  
  267.     debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"",
  268.          cmd, cmd, 
  269.          (cmd == C_NONE) ? len-1 : len-2,
  270.          (cmd == C_NONE) ? msg : msg + 1);
  271.  
  272.     {
  273.         int ramt, wamt=len, woff=0;
  274.         while((ramt = write(rem_w,msg+woff,wamt)) > 0) {
  275.             woff += ramt; wamt -= ramt;
  276.         }
  277.         return ramt<0;
  278.     }
  279. }
  280.  
  281. /*
  282.  * Send a command message to the remote host.
  283.  * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...)
  284.  * The fmt and arg? arguments are optional.
  285.  */
  286. #if    defined(ARG_TYPE) && ARG_TYPE == ARG_STDARG
  287. /*
  288.  * Stdarg frontend to sendcmdmsg()
  289.  */
  290. extern int sendcmd(char cmd, char *fmt, ...)
  291. {
  292.     static char buf[BUFSIZ];
  293.     va_list args;
  294.  
  295.     va_start(args, fmt);
  296.     if (fmt)
  297.         (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args);
  298.     else
  299.         buf[1] = CNULL;
  300.     va_end(args);
  301.  
  302.     return(sendcmdmsg(cmd, buf));
  303. }
  304. #endif    /* ARG_TYPE == ARG_STDARG */
  305.  
  306. #if    defined(ARG_TYPE) && ARG_TYPE == ARG_VARARGS
  307. /*
  308.  * Varargs frontend to sendcmdmsg()
  309.  */
  310. extern int sendcmd(va_alist)
  311.     va_dcl
  312. {
  313.     static char buf[BUFSIZ];
  314.     va_list args;
  315.     char cmd;
  316.     char *fmt;
  317.  
  318.     va_start(args);
  319.     /* XXX The "int" is necessary as a workaround for broken varargs */
  320.     cmd = (char) va_arg(args, int);
  321.     fmt = va_arg(args, char *);
  322.     if (fmt)
  323.         (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args);
  324.     else
  325.         buf[1] = CNULL;
  326.     va_end(args);
  327.  
  328.     return(sendcmdmsg(cmd, buf));
  329. }
  330. #endif    /* ARG_TYPE == ARG_VARARGS */
  331.  
  332. #if    !defined(ARG_TYPE)
  333. /*
  334.  * Stupid frontend to sendcmdmsg()
  335.  */
  336. /*VARARGS2*/
  337. extern int sendcmd(cmd, fmt, a1, a2, a3, a4, a5, a6, a7, a8)
  338.     char cmd;
  339.     char *fmt;
  340. {
  341.     static char buf[BUFSIZ];
  342.  
  343.     if (fmt)
  344.         (void) sprintf((cmd == C_NONE) ? buf : buf + 1, 
  345.                    fmt, a1, a2, a3, a4, a5, a6, a7, a8);
  346.     else
  347.         buf[1] = CNULL;
  348.  
  349.     return(sendcmdmsg(cmd, buf));
  350. }
  351. #endif    /* !ARG_TYPE */
  352.  
  353. /*
  354.  * Internal variables and routines for reading lines from the remote.
  355.  */
  356. static u_char rembuf[BUFSIZ];
  357. static u_char *remptr;
  358. static int remleft;
  359.  
  360. #define remc() (--remleft < 0 ? remmore() : *remptr++)
  361.  
  362. /*
  363.  * Back end to remote read()
  364.  */
  365. static int remread(fd, buf, bufsiz)
  366.     int fd;
  367.     u_char *buf;
  368.     int bufsiz;
  369. {
  370.     return(read(fd, (char *)buf, bufsiz));
  371. }
  372.  
  373. static int remmore()
  374. {
  375.     (void) signal(SIGALRM, sighandler);
  376.     (void) alarm(rtimeout);
  377.  
  378.     remleft = remread(rem_r, rembuf, sizeof(rembuf));
  379.  
  380.     (void) alarm(0);
  381.  
  382.     if (remleft < 0)
  383.         return (-2);    /* error */
  384.     if (remleft == 0)
  385.         return (-1);    /* EOF */
  386.     remptr = rembuf;
  387.     remleft--;
  388.     return (*remptr++);
  389. }
  390.     
  391. /*
  392.  * Read an input line from the remote.  Return the number of bytes
  393.  * stored (equivalent to strlen(p)).  If `cleanup' is set, EOF at
  394.  * the beginning of a line is returned as EOF (-1); other EOFs, or
  395.  * errors, call cleanup() or lostconn().  In other words, unless
  396.  * the third argument is nonzero, this routine never returns failure.
  397.  */
  398. extern int remline(buffer, space, doclean)
  399.     register u_char *buffer;
  400.     int space;
  401.     int doclean;
  402. {
  403.     register int c, left = space;
  404.     register u_char *p = buffer;
  405.  
  406.     if (rem_r < 0) {
  407.         error("Cannot read remote input: Remote descriptor not open.");
  408.         return(-1);
  409.     }
  410.  
  411.     while (left > 0) {
  412.         if ((c = remc()) < -1) {    /* error */
  413.             if (doclean) {
  414.                 finish();
  415.                 /*NOTREACHED*/
  416.             }
  417.             lostconn();
  418.             /*NOTREACHED*/
  419.         }
  420.         if (c == -1) {            /* got EOF */
  421.             if (doclean) {
  422.                 if (left == space)
  423.                     return (-1);/* signal proper EOF */
  424.                 finish();    /* improper EOF */
  425.                 /*NOTREACHED*/
  426.             }
  427.             lostconn();
  428.             /*NOTREACHED*/
  429.         }
  430.         if (c == '\n') {
  431.             *p = CNULL;
  432.  
  433.             if (debug) {
  434.                 static char mbuf[BUFSIZ];
  435.  
  436.                 (void) sprintf(mbuf, 
  437.                     "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"", 
  438.                            buffer[0], buffer[0], 
  439.                            buffer + 1);
  440.  
  441.                 debugmsg(DM_PROTO, "%s", mbuf);
  442.             }
  443.  
  444.             return (space - left);
  445.         }
  446.         *p++ = c;
  447.         left--;
  448.     }
  449.  
  450.     /* this will probably blow the entire session */
  451.     error("remote input line too long");
  452.     p[-1] = CNULL;        /* truncate */
  453.     return (space);
  454. }
  455.  
  456. /*
  457.  * Non-line-oriented remote read.
  458.  */
  459. readrem(p, space)
  460.     char *p;
  461.     register int space;
  462. {
  463.     if (remleft <= 0) {
  464.         /*
  465.          * Set remote time out alarm.
  466.          */
  467.         (void) signal(SIGALRM, sighandler);
  468.         (void) alarm(rtimeout);
  469.  
  470.         remleft = remread(rem_r, rembuf, sizeof(rembuf));
  471.  
  472.         (void) alarm(0);
  473.         remptr = rembuf;
  474.     }
  475.  
  476.     if (remleft <= 0)
  477.         return (remleft);
  478.     if (remleft < space)
  479.         space = remleft;
  480.  
  481.     bcopy((char *) remptr, p, space);
  482.  
  483.     remptr += space;
  484.     remleft -= space;
  485.  
  486.     return (space);
  487. }
  488.  
  489. /*
  490.  * Get the user name for the uid.
  491.  */
  492. extern char *getusername(uid, file, opts)
  493.     UID_T uid;
  494.     char *file;
  495.     opt_t opts;
  496. {
  497.     static char buf[100];
  498.     static UID_T lastuid = (UID_T)-1;
  499.     struct passwd *pwd = NULL;
  500.  
  501.     /*
  502.      * The value of opts may have changed so we always
  503.      * do the opts check.
  504.      */
  505.       if (IS_ON(opts, DO_NUMCHKOWNER)) { 
  506.         (void) sprintf(buf, ":%d", uid);
  507.         return(buf);
  508.       }
  509.  
  510.     /*
  511.      * Try to avoid getpwuid() call.
  512.      */
  513.     if (lastuid == uid && buf[0])
  514.         return(buf);
  515.  
  516.     lastuid = uid;
  517.  
  518.     if ((pwd = getpwuid(uid)) == NULL) {
  519.         message(MT_WARNING,
  520.             "%s: No password entry for uid %d", file, uid);
  521.         (void) sprintf(buf, ":%d", uid);
  522.     } else
  523.         (void) strcpy(buf, pwd->pw_name);
  524.  
  525.     return(buf);
  526. }
  527.  
  528. /*
  529.  * Get the group name for the gid.
  530.  */
  531. extern char *getgroupname(gid, file, opts)
  532.     GID_T gid;
  533.     char *file;
  534.     opt_t opts;
  535. {
  536.     static char buf[100];
  537.     static GID_T lastgid = (GID_T)-1;
  538.     struct group *grp = NULL;
  539.  
  540.     /*
  541.      * The value of opts may have changed so we always
  542.      * do the opts check.
  543.      */
  544.       if (IS_ON(opts, DO_NUMCHKGROUP)) { 
  545.         (void) sprintf(buf, ":%d", gid);
  546.         return(buf);
  547.       }
  548.  
  549.     /*
  550.      * Try to avoid getgrgid() call.
  551.      */
  552.     if (lastgid == gid && buf[0])
  553.         return(buf);
  554.  
  555.     lastgid = gid;
  556.  
  557.     if ((grp = (struct group *)getgrgid(gid)) == NULL) {
  558.         message(MT_WARNING, "%s: No name for group %d", file, gid);
  559.         (void) sprintf(buf, ":%d", gid);
  560.     } else
  561.         (void) strcpy(buf, grp->gr_name);
  562.  
  563.     return(buf);
  564. }
  565.  
  566. /*
  567.  * Read a response from the remote host.
  568.  */
  569. extern int response()
  570. {
  571.     static u_char resp[BUFSIZ];
  572.     u_char *s;
  573.     int n;
  574.  
  575.     debugmsg(DM_CALL, "response() start\n");
  576.  
  577.     n = remline(s = resp, sizeof(resp), 0);
  578.  
  579.     n--;
  580.     switch (*s++) {
  581.         case C_ACK:
  582.         debugmsg(DM_PROTO, "received ACK\n");
  583.         return(0);
  584.     case C_LOGMSG:
  585.         if (n > 0) {
  586.             message(MT_CHANGE, "%s", s);
  587.             return(1);
  588.         }
  589.         debugmsg(DM_PROTO, "received EMPTY logmsg\n");
  590.         return(0);
  591.     case C_NOTEMSG:
  592.         if (s)
  593.             message(MT_NOTICE, "%s", s);
  594.         return(response());
  595.  
  596.     default:
  597.         s--;
  598.         n++;
  599.         /* fall into... */
  600.  
  601.     case C_ERRMSG:    /* Normal error message */
  602.         if (s)
  603.             message(MT_NERROR, "%s", s);
  604.         return(-1);
  605.  
  606.     case C_FERRMSG:    /* Fatal error message */
  607.         if (s)
  608.             message(MT_FERROR, "%s", s);
  609.         finish();
  610.     }
  611.     /*NOTREACHED*/
  612. }
  613.  
  614. /*
  615.  * This should be in expand.c but the other routines call other modules
  616.  * that we don't want to load in.
  617.  *
  618.  * Expand file names beginning with `~' into the
  619.  * user's home directory path name. Return a pointer in buf to the
  620.  * part corresponding to `file'.
  621.  */
  622. extern char *exptilde(ebuf, file)
  623.     char *ebuf;
  624.     register char *file;
  625. {
  626.     register char *s1, *s2, *s3;
  627.     extern char *homedir;
  628.  
  629.     if (*file != '~') {
  630.         (void) strcpy(ebuf, file);
  631.         return(ebuf);
  632.     }
  633.     if (*++file == CNULL) {
  634.         s2 = homedir;
  635.         s3 = NULL;
  636.     } else if (*file == '/') {
  637.         s2 = homedir;
  638.         s3 = file;
  639.     } else {
  640.         s3 = file;
  641.         while (*s3 && *s3 != '/')
  642.             s3++;
  643.         if (*s3 == '/')
  644.             *s3 = CNULL;
  645.         else
  646.             s3 = NULL;
  647.         if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
  648.             if ((pw = getpwnam(file)) == NULL) {
  649.                 error("%s: unknown user name", file);
  650.                 if (s3 != NULL)
  651.                     *s3 = '/';
  652.                 return(NULL);
  653.             }
  654.         }
  655.         if (s3 != NULL)
  656.             *s3 = '/';
  657.         s2 = pw->pw_dir;
  658.     }
  659.     for (s1 = ebuf; *s1++ = *s2++; )
  660.         ;
  661.     s2 = --s1;
  662.     if (s3 != NULL) {
  663.         s2++;
  664.         while (*s1++ = *s3++)
  665.             ;
  666.     }
  667.     return(s2);
  668. }
  669.  
  670. #if    defined(DIRECT_RCMD)
  671. /*
  672.  * Set our effective user id to the user running us.
  673.  * This should be the uid we do most of our work as.
  674.  */
  675. extern int becomeuser()
  676. {
  677.     int r = 0;
  678.  
  679. #if    defined(HAVE_SAVED_IDS)
  680.     r = seteuid(userid);
  681. #else
  682.     r = setreuid(0, userid);
  683. #endif    /* HAVE_SAVED_IDS */
  684.  
  685.     if (r < 0)
  686.         error("becomeuser %d failed: %s (ruid = %d euid = %d)",
  687.               userid, SYSERR, getuid(), geteuid());
  688.  
  689.     return(r);
  690. }
  691. #endif    /* DIRECT_RCMD */
  692.  
  693. #if    defined(DIRECT_RCMD)
  694. /*
  695.  * Set our effective user id to "root" (uid = 0)
  696.  */
  697. extern int becomeroot()
  698. {
  699.     int r = 0;
  700.  
  701. #if    defined(HAVE_SAVED_IDS)
  702.     r = seteuid(0);
  703. #else
  704.     r = setreuid(userid, 0);
  705. #endif    /* HAVE_SAVED_IDS */
  706.  
  707.     if (r < 0)
  708.         error("becomeroot failed: %s (ruid = %d euid = %d)",
  709.               SYSERR, getuid(), geteuid());
  710.  
  711.     return(r);
  712. }
  713. #endif    /* DIRECT_RCMD */
  714.  
  715. /*
  716.  * Set access and modify times of a given file
  717.  */
  718. extern int setfiletime(file, atime, mtime)
  719.     char *file;
  720.     time_t atime;
  721.     time_t mtime;
  722. {
  723. #if    SETFTIME_TYPE == SETFTIME_UTIMES
  724.     struct timeval tv[2];
  725.  
  726.     if (atime != 0 && mtime != 0) {
  727.         tv[0].tv_sec = atime;
  728.         tv[1].tv_sec = mtime;
  729.         tv[0].tv_usec = tv[1].tv_usec = (time_t) 0;
  730.         return(utimes(file, tv));
  731.     } else    /* Set to current time */
  732.         return(utimes(file, (struct timeval *) NULL));
  733.  
  734. #endif    /* SETFTIME_UTIMES */
  735.  
  736. #if    SETFTIME_TYPE == SETFTIME_UTIME
  737.     struct utimbuf utbuf;
  738.  
  739.     if (atime != 0 && mtime != 0) {
  740.         utbuf.actime = atime;
  741.         utbuf.modtime = mtime;
  742.         return(utime(file, &utbuf));
  743.     } else    /* Set to current time */
  744.         return(utime(file, (struct utimbuf *)NULL));
  745. #endif    /* SETFTIME_UTIME */
  746.  
  747. #if    !defined(SETFTIME_TYPE)
  748.     There is no "SETFTIME_TYPE" defined!
  749. #endif    /* SETFTIME_TYPE */
  750. }
  751.  
  752. /*
  753.  * Get version info
  754.  */
  755. extern char *getversion()
  756. {
  757.     static char buff[BUFSIZ];
  758.  
  759.     (void) sprintf(buff,
  760.     "Version %s.%d - Protocol Version %d, Release %s, Patch level %d",
  761.            DISTVERSION, PATCHLEVEL, VERSION, DISTVERSION, PATCHLEVEL);
  762.  
  763.     return(buff);
  764. }
  765.  
  766. /*
  767.  * Execute a shell command to handle special cases.
  768.  * This is now common to both server and client
  769.  */
  770. void runcommand(cmd)
  771.     char *cmd;
  772. {
  773.     int fd[2], pid, i;
  774.     int status;
  775.     register char *cp, *s;
  776.     char sbuf[BUFSIZ], buf[BUFSIZ];
  777.  
  778.     if (pipe(fd) < 0) {
  779.         error("pipe of %s failed: %s", cmd, SYSERR);
  780.         return;
  781.     }
  782.  
  783.     if ((pid = fork()) == 0) {
  784.         /*
  785.          * Return everything the shell commands print.
  786.          */
  787.         (void) close(0);
  788.         (void) close(1);
  789.         (void) close(2);
  790.         (void) open(_PATH_DEVNULL, O_RDONLY);
  791.         (void) dup(fd[PIPE_WRITE]);
  792.         (void) dup(fd[PIPE_WRITE]);
  793.         (void) close(fd[PIPE_READ]);
  794.         (void) close(fd[PIPE_WRITE]);
  795.         (void) execl(_PATH_BSHELL, "sh", "-c", cmd, 0);
  796.         _exit(127);
  797.     }
  798.     (void) close(fd[PIPE_WRITE]);
  799.     s = sbuf;
  800.     *s++ = C_LOGMSG;
  801.     while ((i = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) {
  802.         cp = buf;
  803.         do {
  804.             *s++ = *cp++;
  805.             if (cp[-1] != '\n') {
  806.                 if (s < (char *) &sbuf[sizeof(sbuf)-1])
  807.                     continue;
  808.                 *s++ = '\n';
  809.             }
  810.             /*
  811.              * Throw away blank lines.
  812.              */
  813.             if (s == &sbuf[2]) {
  814.                 s--;
  815.                 continue;
  816.             }
  817.             if (isserver)
  818.                 (void) write(rem_w, sbuf, s - sbuf);
  819.             else {
  820.                 *s = CNULL;
  821.                 message(MT_INFO, "%s", sbuf+1);
  822.             }
  823.             s = &sbuf[1];
  824.         } while (--i);
  825.     }
  826.     if (s > (char *) &sbuf[1]) {
  827.         *s++ = '\n';
  828.         if (isserver)
  829.             (void) write(rem_w, sbuf, s - sbuf);
  830.         else {
  831.             *s = CNULL;
  832.             message(MT_INFO, "%s", sbuf+1);
  833.         }
  834.     }
  835.     while ((i = wait(&status)) != pid && i != -1)
  836.         ;
  837.     if (i == -1)
  838.         status = -1;
  839.     (void) close(fd[PIPE_READ]);
  840.     if (status)
  841.         error("shell returned %d", status);
  842.     else if (isserver)
  843.         ack();
  844. }
  845.  
  846. /*
  847.  * Malloc with error checking
  848.  */
  849. char *xmalloc(amt)
  850.     int amt;
  851. {
  852.     char *ptr;
  853.     extern POINTER *malloc();
  854.  
  855.     if ((ptr = (char *)malloc(amt)) == NULL)
  856.         fatalerr("Cannot malloc %d bytes of memory.", amt);
  857.  
  858.     return(ptr);
  859. }
  860.  
  861. /*
  862.  * realloc with error checking
  863.  */
  864. char *xrealloc(baseptr, amt)
  865.     char *baseptr;
  866.     unsigned int amt;
  867. {
  868.     char *new;
  869.     extern POINTER *realloc();
  870.  
  871.     if ((new = (char *)realloc(baseptr, amt)) == NULL)
  872.         fatalerr("Cannot realloc %d bytes of memory.", amt);
  873.  
  874.     return(new);
  875. }
  876.  
  877. /*
  878.  * calloc with error checking
  879.  */
  880. char *xcalloc(num, esize)
  881.     unsigned num;
  882.     unsigned esize;
  883. {
  884.     char *ptr;
  885.     extern POINTER *calloc();
  886.  
  887.     if ((ptr = (char *)calloc(num, esize)) == NULL)
  888.         fatalerr("Cannot calloc %d * %d = %d bytes of memory.",
  889.               num, esize, num * esize);
  890.  
  891.     return(ptr);
  892. }
  893.  
  894. extern char *basename(path)
  895.     const char *path;
  896. {
  897.     register char *cp;
  898.  
  899.     if (cp = strrchr(path, '/'))
  900.         return(cp+1);
  901.     else
  902.         return(path);
  903. }
  904.  
  905. /*
  906.  * Take a colon (':') seperated path to a file and
  907.  * search until a component of that path is found and
  908.  * return the found file name.
  909.  */
  910. extern char *searchpath(path)
  911.     char *path;
  912. {
  913.     register char *cp;
  914.     register char *file;
  915.     struct stat statbuf;
  916.  
  917.     for (; ;) {
  918.         if (!path)
  919.             return((char *) NULL);
  920.         file = path;
  921.         cp = strchr(path, ':');
  922.         if (cp) {
  923.             path = cp + 1;
  924.             *cp = CNULL;
  925.         } else
  926.             path = NULL;
  927.         if (stat(file, &statbuf) == 0)
  928.             return(file);
  929.         /* Put back what we zapped */
  930.         if (path)
  931.             *cp = ':';
  932.     }
  933. }
  934.  
  935. /*
  936.  * Set line buffering.
  937.  */
  938. extern int
  939. mysetlinebuf(fp)
  940.     FILE *fp;
  941. {
  942. #if    SETBUF_TYPE == SETBUF_SETLINEBUF
  943.     return(setlinebuf(fp));
  944. #endif    /* SETBUF_SETLINEBUF */
  945. #if    SETBUF_TYPE == SETBUF_SETVBUF
  946.     return(setvbuf(stdout, NULL, _IOLBF, BUFSIZ));
  947. #endif    /* SETBUF_SETVBUF */
  948. #if    !defined(SETBUF_TYPE)
  949.     No SETBUF_TYPE is defined!
  950. #endif    /* SETBUF_TYPE */
  951. }
  952.  
  953. /*
  954.  * Our interface to system call to get a socket pair.
  955.  */
  956. int
  957. getsocketpair(domain, type, protocol, sv)
  958.     int domain;
  959.     int type;
  960.     int protocol;
  961.     int sv[];
  962. {
  963. #if    SOCKPAIR_TYPE == SOCKPAIR_SOCKETPAIR
  964.     return(socketpair(domain, type, protocol, sv));
  965. #endif    /* SOCKPAIR_SOCKETPAIR */
  966. #if    SOCKPAIR_TYPE == SOCKPAIR_SPIPE
  967.     return(spipe(sv));
  968. #endif    /* SOCKPAIR_SPIPE */
  969. #if    !defined(SOCKPAIR_TYPE)
  970.     No SOCKPAIR_TYPE is defined!
  971. #endif    /* SOCKPAIR_TYPE */
  972. }
  973.